﻿using System;
using System.Collections.Generic;
using System.Linq;
using MugenMvvmToolkit.Interfaces;
using MugenMvvmToolkit.Utils;

namespace MugenMvvmToolkitTest.TestInfrastructure
{
    public class TestValidationProvider : IValidationProvider
    {
        #region Properties

        public Type TypeToValidate { get; set; }

        public readonly List<object> ValidateObjects = new List<object>();

        public IDictionary<object, object> ValidationMetadata { get; set; }

        public readonly Dictionary<string, List<IValidationResult>> Errors = new Dictionary<string, List<IValidationResult>>();

        public string ValidatePropertyName { get; set; }

        public object ValidatePropertyObject { get; set; }

        #endregion

        #region Implementation of IValidationProvider

        /// <summary>
        ///     Determines whether the specified object is valid using the validation context.
        /// </summary>
        /// <param name="instance">The object to validate.</param>
        /// <param name="breakOnFirstError">
        ///     If <c>true</c> break check on first error, otherwise <c>false</c>.
        /// </param>
        /// <param name="validationResults">The collection to write validation results.</param>
        /// <param name="validationMetadata">The specified validation metadata. It's optional parameter.</param>
        public void ValidateObject(object instance, bool breakOnFirstError, IList<IValidationResult> validationResults,
                                   IDictionary<object, object> validationMetadata)
        {
            ValidateObjects.Add(instance);
            ValidationMetadata = validationMetadata;
            if (TypeToValidate != null && instance.GetType() != TypeToValidate)
                return;
            foreach (IValidationResult validationResult in Errors.SelectMany(pair => pair.Value))
                validationResults.Add(validationResult);
        }

        /// <summary>
        ///     Determines whether the specified object property is valid using the validation context.
        /// </summary>
        /// <param name="instance">The object to validate.</param>
        /// <param name="propertyName">The specified property name to validate.</param>
        /// <param name="validationResults">The collection to write validation results.</param>
        /// <param name="validationMetadata">The specified validation metadata. It's optional parameter.</param>
        public void ValidateProperty(object instance, string propertyName, IList<IValidationResult> validationResults,
                                     IDictionary<object, object> validationMetadata)
        {
            ValidatePropertyObject = instance;
            ValidatePropertyName = propertyName;
            ValidationMetadata = validationMetadata;
            if (TypeToValidate != null && instance.GetType() != TypeToValidate)
                return;
            List<IValidationResult> results;
            Errors.TryGetValue(propertyName, out results);
            if (results == null) return;
            foreach (IValidationResult validationResult in results)
                validationResults.Add(validationResult);
        }

        /// <summary>
        ///     Fills errors from validation result to dictionary.
        /// </summary>
        /// <param name="validationResults">The collection with validation results.</param>
        /// <param name="dictionary">
        ///     An instance of <see cref="System.Collections.Generic.IDictionary{TKey,TValue}" />
        /// </param>
        public void FillErrors(IList<IValidationResult> validationResults,
                               IDictionary<string, IList<IValidationResult>> dictionary)
        {
            MugenMvvmToolkit.Should.NotBeNull(validationResults, "validationResults");
            MugenMvvmToolkit.Should.NotBeNull(dictionary, "dictionary");
            for (int index = 0; index < validationResults.Count; index++)
            {
                IValidationResult validationResult = validationResults[index];
                if (validationResult.IsValid) continue;
                foreach (string result in validationResult.MemberNames.Where(s => s != null))
                {
                    IList<IValidationResult> values;
                    if (!dictionary.TryGetValue(result, out values))
                    {
                        values = new List<IValidationResult>();
                        dictionary[result] = values;
                    }
                    values.Add(validationResult);
                }
            }
        }

        #endregion
    }
}